package com.itrui.encrypted_transmission;

import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.util.encoders.Hex;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.ArrayList;

public class Client {

    public static void main(String[] args) throws IOException, InterruptedException {
        //连接服务端 (ip , 端口）
        InetAddress localHost = InetAddress.getLocalHost();
        System.out.println("本机ip（服务端）：" + localHost.toString());
        //连接本机的 8888端口, 如果连接成功，返回Socket对象
        Socket socket = new Socket(localHost, 6666);
        System.out.println("客户端，连接端口:" + socket.getPort());

        //1、生成公钥和私钥
        String publicKeyHex = null;
        String privateKeyHex = null;
        KeyPair keyPair = SM2Utils.createECKeyPair();
        PublicKey publicKey = keyPair.getPublic();
        if (publicKey instanceof BCECPublicKey) {
            //获取65字节非压缩缩的十六进制公钥串(0x04)
            publicKeyHex = Hex.toHexString(((BCECPublicKey) publicKey).getQ().getEncoded(false));
            System.out.println("---->SM2公钥：" + publicKeyHex);
        }
        PrivateKey privateKey = keyPair.getPrivate();
        if (privateKey instanceof BCECPrivateKey) {
            //获取32字节十六进制私钥串
            privateKeyHex = ((BCECPrivateKey) privateKey).getD().toString(16);
            System.out.println("---->SM2私钥：" + privateKeyHex);
        }

        //2、遍历文件夹下的文件，封装成自定义文件对象,并用Base64编码把文件成String
        ArrayList<MyFile> files = toMyFiles("D:\\RuiProject\\FileTest");
        //4、序列化对象并且加密
        //String serialize = JOSNUtils.serialize(files.get(0));
        //String encrypt = SM2Utils.encrypt(publicKeyHex, serialize);
        //5、序列化对象到临时文件（防止文件过大）
        //toTemp(encrypt);
        //6、把临时文件中的内容和私钥发送到服务端
        //sendToServer(socket.getOutputStream(), privateKeyHex,files.size());

        int len = 0;
        byte[] bytes = new byte[1024];
        DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
        dos.writeUTF(privateKeyHex);
        dos.flush();

        dos.writeInt(files.size());
        dos.flush();


        try {
            System.out.println("正在发送...");
            //4、序列化对象并且加密
            String serialize = JOSNUtils.serialize(files.get(0));
            String encrypt = SM2Utils.encrypt(publicKeyHex, serialize);
            //5、序列化对象到临时文件（防止文件过大）
            toTemp(encrypt);
            FileInputStream fis = new FileInputStream("D:\\RuiProject\\temp\\temp.txt");
            while ((len = fis.read(bytes)) != -1) {
                dos.write(bytes, 0, len);
            }



        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        socket.shutdownOutput();

        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String msg = br.readLine();
        System.out.println("来自服务器的消息：" + msg);


        //关闭流对象,socket,刷新，添加终止符
        //bufferedInputStream.close();
        dos.flush();

        //7、关闭流
        dos.close();
        socket.close();

    }

    /**
     * 把临时文件中的内容和私钥发送到服务端
     *
     * @param os
     * @param privateKeyHex
     * @throws IOException
     */
    public static void sendToServer(OutputStream os, String privateKeyHex, int num) throws IOException {
        int len = 0;
        byte[] bytes = new byte[1024];
        DataOutputStream dos = new DataOutputStream(os);
        dos.writeUTF(privateKeyHex);
        dos.flush();

        dos.writeInt(num);
        dos.flush();

        try {
            FileInputStream fis = new FileInputStream("D:\\RuiProject\\temp\\temp.txt");
            while ((len = fis.read(bytes)) != -1) {
                dos.write(bytes, 0, len);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        dos.flush();
        dos.close();
    }


    /**
     * 序列化的对象写入临时文件
     *
     * @param data
     */
    public static void toTemp(String data) {
        try {
            FileOutputStream fos = new FileOutputStream("D:\\RuiProject\\temp\\temp.txt");
            fos.write(data.getBytes());
            fos.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    /**
     * 将文件列表封装成自定义文件对象
     *
     * @param path
     * @return
     */
    public static ArrayList<MyFile> toMyFiles(String path) {
        File dic = new File(path);
        String[] filesName = dic.list();

        ArrayList<MyFile> files = new ArrayList<>();
        for (int i = 0; i < filesName.length; i++) {
            File file = new File(path + "\\" + filesName[i]);
            if (file.isFile() && file.exists()) {
                MyFile myFile = new MyFile();
                myFile.setSize(file.length());
                myFile.setName(filesName[i]);
                String pic = CodeUtils.encodeFile(path + "\\" + filesName[i]);
                myFile.setFile(pic);
                files.add(myFile);
            }
        }
        return files;
    }

}
